﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using JoystickInterface;
using System.IO.Ports;
using System.Reflection;
using System.Xml;
using System.IO;

namespace JoypadParser
{
    public partial class Form1 : Form
    {
        // in design ho aggiungo per comodità in debug un button Stop per fermare il timer.

        const string TESTSTRING = "##TEST##";

        Joystick jst;
        UdpClient udp;
        int _joyMessageNumber = 0;
        SerialPort serial;

        bool joyAcquired = false;
        //int MAXBUTTONS = 10;
        bool flgTest = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            UpdateJoystickList();
        }

        private void UpdateJoystickList()
        {
            jst = new JoystickInterface.Joystick(this.Handle);
            string[] sticks = jst.FindJoysticks();
            if (sticks != null)
            {
                foreach (string s in sticks)
                {
                    cbJoys.Items.Add(s);
                }
            }
            cbJoys.Items.Add(TESTSTRING);
            if (cbJoys.Items.Count > 0)
            {
                cbJoys.SelectedIndex = 0;
            }
        }


        private void tmrUpdate_Tick(object sender, EventArgs e)
        {
            IFormatProvider fp;
            string message = "";
            byte[] sstream = new byte[0];
            fp = System.Globalization.CultureInfo.InvariantCulture;
            if (flgTest)
            {
                //message = string.Format(fp, "E {0} {1} {2} {3} {4} {5}", 0, 512, 500, 600, 1, _joyMessageNumber);
                message = new JoyPacket(0, 512, 500, 600, 1).ToString();
                sstream = Binary.CreatePacketBytes(0, 512, 500, 600, 1, _joyMessageNumber);
            }
            else
            {
                jst.UpdateStatus();
                message = new JoyPacket(jst).ToString();
                sstream = new JoyPacket(jst).ToBinary();
            }
            tbDebug.Items.Add(message);
            tbDebug.SelectedIndex = tbDebug.Items.Count - 1;

            if (udp != null)
            {
                try
                {
                    if (_isBinaryMode.Checked) //è stato selezionato il protocollo binario
                        udp.Send(sstream, sstream.Length);
                    else if (_isStringMode.Checked) //è stato selezionato il protocollo ASCII
                    {
                        sstream = UTF8Encoding.UTF8.GetBytes(message);
                        udp.Send(sstream,sstream.Length);
                    }
                }
                catch (Exception ex)
                {
                    tbDebug.Items.Add(ex.Message);
                }
            }
            if (serial != null)
            {
                try
                {
                    serial.Write(sstream, 0, sstream.Length);
                }
                catch (Exception ex)
                {
                    tbDebug.Items.Add(ex.Message);
                }
            }
        }
   
        private void Connect_Click(object sender, EventArgs e)
        {
            try
            {
                if (cbUDP.Checked)
                {
                    udp = new UdpClient(tbIP.Text, Int32.Parse(tbPort.Text));
                    udp.DontFragment = true;
                }
                if (cbSerial.Checked)
                {
                    //Enable serial interface
                    int BaudeRate = 0;
                    BaudeRate = Convert.ToInt32(_BaudRateTxt.Text);
                    serial = new SerialPort(tbSerialPort.Text, BaudeRate); //BaudeRate = 9600
                    serial.Open();
                }
                // grab the joystick
                if (cbJoys.SelectedItem.ToString() == TESTSTRING)
                {
                    flgTest = true;
                }
                else
                {
                    joyAcquired = jst.AcquireJoystick(cbJoys.SelectedItem.ToString());
                    if (joyAcquired)
                    {
                        LoadJoystickSettings(jst);
                    }
                }

                if (tmrUpdate.Interval != Convert.ToInt32(_freqInMs.Text) && _freqInMs.Text != String.Empty)
                {
                    tmrUpdate.Interval = Convert.ToInt32(_freqInMs.Text);
                }
                tmrUpdate.Enabled = true;
            }
            catch (Exception ex)
            {
                tbDebug.Items.Add(ex.Message);
            }
        }

        private void LoadJoystickSettings(Joystick jst)
        {
            string filename = Constants.GetSettingsFile(jst);

            bool[] inv = new bool[4];

            XmlDocument document = new XmlDocument();
            try
            {
                document.Load(filename);
                PropertyInfo[] settings = new PropertyInfo[4];
                int i = 0;
                foreach (XmlNode item in document.SelectNodes("/joypad/asse"))
                {
                    Type type = jst.GetType();
                    string prop = item.InnerText;

                    settings[i] = type.GetProperty(prop);
                    inv[i] = XmlConvert.ToBoolean(item.Attributes["inverted"].Value);
                    i++;
                }
                jst.Settings = settings;

                //setto i boolean per i valori invertiti
                //inv[0] = false;
                //inv[1] = true;
                //inv[2] = false;
                //inv[3] = false;

                jst.InvertedAxis = inv;


            }
            catch (FileNotFoundException ex)
            {
                MessageBox.Show("Errore! Settare impostazioni!");
                Form form = new JoypadSettingsForm(jst);
                form.ShowDialog();
            }
        }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (joyAcquired)
            {
                jst.ReleaseJoystick();
            }
            if (serial != null)
            {
                serial.Close();
            }
            if (udp != null)
                udp.Close();
        }

        private void Stop_Click(object sender, EventArgs e)
        {
            tmrUpdate.Enabled = false;
        }

        private void joyPadSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (cbJoys.SelectedItem.ToString() != TESTSTRING)
            {
                Form form = new JoypadSettingsForm(jst);
                form.Show();
            }
        }

        private void refreshJoystickListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string[] sticks = jst.FindJoysticks();
            if (sticks != null)
            {
                if (sticks.Length < cbJoys.Items.Count)
                {
                    cbJoys.Items.Clear();
                    foreach (string s in sticks)
                    {
                        cbJoys.Items.Add(s);
                    }
                    cbJoys.Items.Add(TESTSTRING);
                    if (cbJoys.Items.Count > 0)
                    {
                        cbJoys.SelectedIndex = 0;
                    }
                }
                else
                {
                    foreach (string item in sticks)
                    {
                        if (!cbJoys.Items.Contains(item))
                        {
                            // se arrivo qua il joystick item è nuovo
                            cbJoys.Items.Add(item);
                            cbJoys.SelectedIndex = cbJoys.Items.Count - 1;

                            if (DialogResult.Yes == MessageBox.Show("Setting option for " + item + "?", "New Joystick found", MessageBoxButtons.YesNo))
                                joyPadSettingsToolStripMenuItem_Click(sender, e);
                        }
                    }
                }
            }
            else // vuol dire che non ho + joystick collegati
            {
                cbJoys.Items.Clear();
                cbJoys.Items.Add(TESTSTRING);
                cbJoys.SelectedIndex = 0;
            }
        }

        private void cbJoys_SelectedIndexChanged(object sender, EventArgs e)
        {
            jst.SetCurrentJoy((string)cbJoys.SelectedItem);
        }
    }
}
